package com.common.base.http

import androidx.lifecycle.viewModelScope
import com.common.base.base.BaseResponse
import com.common.base.base.BaseVM
import com.common.base.http.exceptions.CloudException
import com.common.base.http.main.ApiConfig
import com.common.base.http.main.CODE_SUCCESS
import com.common.base.http.main.CODE_TOKEN_INVALID
import com.common.base.http.main.CODE_UNKNOWN
import com.common.base.tools.obj.LoadingObj
import com.common.base.tools.utils.logger
import kotlinx.coroutines.launch
import java.lang.reflect.Field
import kotlin.reflect.full.createInstance


/**
 * 网络请求统一请求
 * @param request Retrfit 接口，取最后一个协议结果作为T的返回值
 * @param response 断言Reqeust 返回T 作为Reponse 返回T
 */
@Deprecated("过时")
inline fun <reified T : BaseResponse> BaseVM.requestApi(
    crossinline request: suspend () -> T,
    crossinline response: suspend (responseBean: T) -> Unit,
    isShowLoading: Boolean = false,
) {
    viewModelScope.launch {
        try {
            if (isShowLoading) LoadingObj.showLoad()
            val bean = request.invoke().apiResponse()
            if (isShowLoading) LoadingObj.hintLoad()
            response.invoke(bean)
        } catch (e: java.lang.Exception) {
            e.printStackTrace()
            if (isShowLoading) LoadingObj.hintLoad()
            val cloudException = CloudException.accept(e)
            logger.error(cloudException.message)
            val newBean = T::class.createInstance()
            //获取父类的属性
            val fieldCode = getDeclaredField(newBean, ApiConfig.CODE_NAME)
            val fieldMessage = getDeclaredField(newBean, ApiConfig.MESSAGE_NAME)
            fieldMessage?.isAccessible = true
            fieldCode?.isAccessible = true
            fieldCode?.set(newBean, cloudException.code)
            fieldMessage?.set(newBean, cloudException.message)
            response.invoke(newBean)
        }
    }
}

/**
 * 网络请求统一请求
 * @param request Retrfit 接口，取最后一个协议结果作为T的返回值
 * @param response 断言Reqeust 返回T 作为Reponse 返回T
 */
inline fun <reified T : BaseResponse> requestApi(
    request: () -> T,
    isShowLoading: Boolean? = false,
): T {
    try {
        if (isShowLoading!!) LoadingObj.showLoad()
        val bean = request.invoke().apiResponse()
        if (isShowLoading) LoadingObj.hintLoad()
        return bean
    } catch (e: java.lang.Exception) {
        e.printStackTrace()
        if (isShowLoading!!) LoadingObj.hintLoad()
        val cloudException = CloudException.accept(e)
        logger.error(cloudException.message)
        val newBean = T::class.createInstance()
        val fieldCode = getDeclaredField(newBean, ApiConfig.CODE_NAME)
        val fieldMessage = getDeclaredField(newBean, ApiConfig.MESSAGE_NAME)
        fieldMessage?.isAccessible = true
        fieldCode?.isAccessible = true
        fieldCode?.set(newBean, cloudException.code)
        fieldMessage?.set(newBean, cloudException.message)
        return newBean
    }
}


/**
 * 统一结果解析
 * 验证token
 */
inline fun <reified T> T.apiResponse(): T {
    val response = this
    try {
        val obj = response!!::class.java
        //获取父类的属性
        var fieldCode = getDeclaredField(response, ApiConfig.CODE_NAME)
        var fieldMessage = getDeclaredField(response, ApiConfig.MESSAGE_NAME)
        if (fieldCode == null) {
            //补偿-获取子类的属性
            fieldCode = obj.getDeclaredField(ApiConfig.CODE_NAME)
            fieldMessage = obj.getDeclaredField(ApiConfig.CODE_NAME)
        }
        fieldMessage?.isAccessible = true
        fieldCode?.isAccessible = true
        when (val code = fieldCode?.get(response)) {
            CODE_TOKEN_INVALID -> {//过滤token失效
                //todo 跳转到登录页
                throw CloudException(code as Int, fieldMessage?.get(response) as String)
            }

            CODE_SUCCESS ->
                return response

            else ->
//                return response
                return response
        }
    } catch (e: Exception) {
        throw CloudException(code = CODE_UNKNOWN, message = e.message, e)
    }
}


/**
 * 循环向上转型, 获取对象的 DeclaredField
 * @param object : 子类对象
 * @param fieldName : 父类中的属性名
 * @return 父类中的属性对象
 */
fun getDeclaredField(`object`: Any, fieldName: String?): Field? {
    var field: Field?
    var clazz: Class<*> = `object`.javaClass
    while (clazz != Any::class.java) {
        try {
            field = clazz.getDeclaredField(fieldName)
            return field
        } catch (e: Exception) {
            //这里甚么都不要做！并且这里的异常必须这样写，不能抛出去。
            //如果这里的异常打印或者往外抛，则就不会执行clazz = clazz.getSuperclass(),最后就不会进入到父类中了
        }
        clazz = clazz.superclass
    }
    return null
}